package com.example.util;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.*;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

/**
 * @Classname ScanClassUtils
 * @Description TODO
 * @Date 2023/4/24 14:58
 * @Created by XiongXiong
 * @Author: X.I.O
 *
 * 类扫描工具类
 */
public class JarScanClassUtils {

    public static void clear(){
        //classSet.clear();
    }

    private static Set<Class<?>> classSet=new HashSet<>();

    public static void addAllSet(Set<Class<?>> cls){
        classSet.addAll(cls);
    }

    public static Set<Class<?>> getClassSet(){
        return JarScanClassUtils.classSet;
    }


    public static Set<Class<?>> loadAllJarFromAbsolute(String directoryPath) throws
            NoSuchMethodException, InvocationTargetException, IllegalAccessException, IOException {
        Set< Class< ? >> set=new HashSet<>();
        File directory = null;
        directory=new File(directoryPath);
        // 判断是否为文件夹，如果是文件,直接用单个jar解析的方法去解析
        if (!directory.isDirectory()) {
            // 添加jar扫描路径
            addUrl(directory);
            return loadJarFromAbsolute(directoryPath,set);
        }
        // 如果是文件夹，则需要循环加载当前文件夹下面的所有jar
        //Map<String, Object> clazzMap = new HashMap<>(16);
        File[] jars = directory.listFiles();
        if (jars != null && jars.length > 0) {
            List<String> jarPath = new LinkedList<>();
            for (File file : jars) {
                String fPath = file.getPath();
                // 只加载jar
                if (fPath.endsWith(".jar")) {
                    addUrl(file);
                    jarPath.add(fPath);
                }
            }
        }
        return set;
    }

    private static Set<Class<?>> loadJarFromAbsolute(String path,Set<Class<?>> set) throws IOException {
        try {
            System.out.println(path);
            JarFile jar = new JarFile(path);
            Enumeration<JarEntry> entryEnumeration = jar.entries();
            Map<String, Object> clazzMap = new HashMap<>(32);
            while (entryEnumeration.hasMoreElements()) {
                JarEntry entry = entryEnumeration.nextElement();

                // 先获取类的名称，符合条件之后再做处理，避免处理不符合条件的类
                String clazzName = entry.getName();

                if (clazzName.endsWith(".class")  ) {
                    // 去掉文件名的后缀
                    clazzName = clazzName.substring(0, clazzName.length() - 6);
                    // 替换分隔符
                    clazzName = clazzName.replace("/", ".");
                    // 加载类,如果失败直接跳过

                    URLClassLoader classLoader = LoadJarUtils.getUrlClassLoader();
                    //cl.loadClass()
                    try {
                        Class<?> clazz=classLoader.loadClass(clazzName);
                        set.add(clazz);
                    } catch (Throwable e) {
                        // 这里可能出现有些类是依赖不全的，直接跳过，不做处理，也没法做处理
                    }
                }
            }
        }catch (Exception e) {
            e.printStackTrace();
        }

        return set;
    }

    private static void addUrl(File jarPath) throws NoSuchMethodException, InvocationTargetException,
            IllegalAccessException, MalformedURLException {
        LoadJarUtils.reloadJar(jarPath.getPath());
        URLClassLoader classLoader = LoadJarUtils.getUrlClassLoader();
        //URLClassLoader classLoader = (URLClassLoader) ClassLoader.getSystemClassLoader();
        Method method = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
        if (!method.isAccessible()) {
            method.setAccessible(true);
        }
        URL url = jarPath.toURI().toURL();

        // 把当前jar的路径加入到类加载器需要扫描的路径
        method.invoke(classLoader, url);
    }



}
